package com.dymall.pay.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dymall.api.client.UserClient;
import com.dymall.common.exception.BizIllegalException;
import com.dymall.common.utils.BeanUtils;
import com.dymall.common.utils.UserContext;
import com.dymall.pay.domain.dto.PayApplyDTO;
import com.dymall.pay.domain.dto.PayOrderFormDTO;
import com.dymall.pay.domain.po.Order;
import com.dymall.pay.domain.po.PayOrder;
import com.dymall.pay.enums.PayStatus;
import com.dymall.pay.mapper.PayMapper;
import com.dymall.pay.service.PayService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Slf4j
@Service
@RequiredArgsConstructor
public class PayServiceImpl extends ServiceImpl<PayMapper, PayOrder> implements PayService {
    private final UserClient userClient;
    private final RabbitTemplate rabbitTemplate;

    @Override
    public String createPayOrder(PayApplyDTO payApplyDTO) {
        // 1.幂等性校验
        PayOrder payOrder = checkIdempotent(payApplyDTO);
        // 2.返回结果
        return payOrder.getId().toString();
    }

    @Override
    @Transactional
    public void tryPayOrderByBalance(PayOrderFormDTO pay) {
        // 1.查询支付单
        PayOrder payOrder = getById(pay.getId());
        // 2.判断状态
        if(!PayStatus.WAIT_BUYER_PAY.equalsValue(payOrder.getStatus())){
            // 订单不是未支付，状态异常
            throw new BizIllegalException("交易已支付或关闭！");
        }
        // 3.尝试扣减余额
        userClient.deductMoney(pay.getPw(), payOrder.getAmount());
        // 4.修改支付单状态
        boolean success = markPayOrderSuccess(pay.getId(), LocalDateTime.now());
        if (!success) {
            throw new BizIllegalException("交易已支付或关闭！");
        }
        // 5.修改订单状态
        /*
        Order order = new Order();
        order.setId(pay.getId());
        order.setStatus(2);
        order.setPayTime(LocalDateTime.now());
        orderService.updateById(order);
         */
        try {
            //向消息队列发送消息
            rabbitTemplate.convertAndSend("pay.topic", "pay.success", pay.getId());
        }
        catch (Exception e){
            log.error("修改订单状态错误，订单号为{}",pay.getId(), e);
        }
    }

    private boolean markPayOrderSuccess(Long id, LocalDateTime success) {
        return lambdaUpdate()
                .set(PayOrder::getPaySuccessTime, success)
                .set(PayOrder::getStatus, PayStatus.TRADE_SUCCESS.getValue())
                .eq(PayOrder::getId, id)
                // 支付状态的乐观锁判断
                .in(PayOrder::getStatus, PayStatus.NOT_COMMIT.getValue(), PayStatus.WAIT_BUYER_PAY.getValue())
                .update();
    }

    private PayOrder checkIdempotent(PayApplyDTO payApplyDTO) {
        // 1.首先查询支付单
        PayOrder order = lambdaQuery()
                .eq(PayOrder::getBizOrderNo, payApplyDTO.getBizOrderNo())
                .one();
        // 2.判断是否存在
        if(order == null){
            // 不存在支付单，说明是第一次，写入新的支付单并返回
            PayOrder payOrder = buildPayOrder(payApplyDTO);
            payOrder.setPayOrderNo(IdWorker.getId());
            save(payOrder);
            return payOrder;
        }
        // 3.旧单已经存在，判断是否支付成功
        if(PayStatus.TRADE_SUCCESS.equalsValue(order.getStatus())){
            // 已经支付成功，抛出异常
            throw new BizIllegalException("订单已经支付！");
        }
        // 4.旧单已经存在，判断是否已经关闭
        if(PayStatus.TRADE_CLOSED.equalsValue(order.getStatus())){
            // 已经关闭，抛出异常
            throw new BizIllegalException("订单已关闭");
        }
        // 5.旧单已经存在，判断支付渠道是否一致
        if(!StringUtils.equals(order.getPayChannelCode(), payApplyDTO.getPayChannelCode())){
            // 支付渠道不一致，需要重置数据，然后重新申请支付单
            PayOrder payOrder = buildPayOrder(payApplyDTO);
            payOrder.setId(order.getId());
            payOrder.setQrCodeUrl("");
            updateById(payOrder);
            payOrder.setPayOrderNo(order.getPayOrderNo());
            return payOrder;
        }
        // 6.旧单已经存在，且可能是未支付或未提交，且支付渠道一致，直接返回旧数据
        return order;
    }

    private PayOrder buildPayOrder(PayApplyDTO payApplyDTO) {
        // 1.数据转换
        PayOrder payOrder = BeanUtils.toBean(payApplyDTO, PayOrder.class);
        // 2.初始化数据
        payOrder.setPayOverTime(LocalDateTime.now().plusMinutes(120L));
        payOrder.setStatus(PayStatus.WAIT_BUYER_PAY.getValue());
        payOrder.setBizUserId(UserContext.getUser());
        return payOrder;
    }
}
